/**
 * 负责编译模板，解析指令/插值表达式
 * 负责页面的首次渲染
 * 当数据变化后重新渲染视图
 */
class Compiler {
  constructor (vm) {
    this.vm  = vm
    this.el = vm.$el
    this.compiler(this.el)
  }
  // 编译模板，负责解析文本节点和元素节点
  compiler (el) {
    // 获取根元素下的子节点
    const children = el.childNodes
    //遍历子节点
    Array.from(children).forEach(node => {
      // 文本节点
      if (this.isTextNode(node)) {
        this.compilerText(node)
      }
      // 元素节点
      if ( this.isElementNode(node) ) {
        this.compilerElement (node)
      }
      
      if (node.childNodes && node.childNodes.length) {
        // 如果当前节点中还有子节点，递归编译
        this.compiler(node)
      }
    })

  }

  // 解析文本节点
  compilerText (node) {
    const reg = /\{\{(.+)\}\}/    
    let text = node.textContent
    //正则表达式匹配文本中是否包含 差值表达式
    if (reg.test(text)) {
      // 插值表达式中的值就是我们要的属性名称
      const key = RegExp.$1.trim()
      // 从vm 实例中找到对应的值，替换掉文本内容
      node.textContent = this.vm[key]
      // 实例化Watcher，当当前属性的数据发生变化时，通过回调函数更新视图
      new Watcher(this.vm, key, value => {
        node.textContent = value
      })
    }

  }

  // 负责编译元素的指令
  // 处理v-text , v-model
  compilerElement (node) {
    Array.from(node.attributes).forEach(attr => {
      // 获取属性名称
      let attrName = attr.name
      if (this.isDirective(attrName)) {
        const key = attr.value
        const dir = attrName.substr(2)
        this.update(node, dir, key)
      }

    })
  }
  
  update (node, dir, key) {
    let updaterFn
    // dir: 'on:click="fn"'
    if (this.isVonDirective(dir)) {
      let arr = dir.split(':')
      const re = arr[1] + "=" + key
      const pre = arr[0]
      updaterFn = this[pre + 'Updater']
      updaterFn && updaterFn.call(this,node,re)
    }else {
      updaterFn = this[dir + 'Updater']
      updaterFn && updaterFn.call(this,node,key)
      
    }
    
    
  }
  
  // v-on 指令 key 为 click="fn"
  onUpdater (node, key) {
    const arr = key.split('=')
    const event = arr[0], attr = arr[1].includes('(') ? arr[1].split('(')[0] : arr[1]
    let reg = /\((.+?)\)/
    let params = ""
    if (reg.test(arr[1])) {
      // 正则表达式匹配出括号中传递的参数
      params = RegExp.$1.trim()
    }
    // 注册监听事件
    node.addEventListener(event, () => {
      this.vm[attr](params)
    })
  }
  // v-html 指令
  htmlUpdater ( node, key ) {
    node.innerHTML = this.vm[key]
    new Watcher (this.vm, key, value => {
      node.innerHTML = value
    })
  }
  // v-text 指令编译
  textUpdater (node, key) {
    node.textContent =  this.vm[key]
    new Watcher (this.vm, key, value => {
      node.textContent = value
    } )
    // node.textContent = this.vm[key]
    
  }
  // v-model指令编译
  modelUpdater (node, key) {
    node.value = this.vm[key]
    new Watcher (this.vm, key, value => {
      node.value = value
    } )
    // 文本框添加input 监听事件
    node.addEventListener('input', () => {
      this.vm[key] = node.value
    })
    
  }
  //判断是否是绑定事件的指令
  isVonDirective (attr) {
    return attr.includes(":")
  }
  // 判断是否是指令
  isDirective (attrName) {
    return attrName.startsWith('v-')
  }
  
  // 判断是否是文本节点
  isTextNode (node) {
    return node.nodeType === 3
  }

  // 判断是否是元素节点
  isElementNode (node) {
    return node.nodeType === 1
  }

}